home *** CD-ROM | disk | FTP | other *** search
/ Celestin Apprentice 5 / Apprentice-Release5.iso / Source Code / C / Applications / Python 1.3.3 / Python 133 SRC / Demo / tkinter / guido / ShellWindow.py < prev    next >
Text File  |  1995-12-21  |  4KB  |  165 lines

  1. import os
  2. import sys
  3. import string
  4. from Tkinter import *
  5. from ScrolledText import ScrolledText
  6. from Dialog import Dialog
  7. import signal
  8.  
  9. TK_READABLE  = 1
  10. TK_WRITABLE  = 2
  11. TK_EXCEPTION = 4
  12.  
  13. BUFSIZE = 512
  14.  
  15. class ShellWindow(ScrolledText):
  16.  
  17.     def __init__(self, master = None, cnf = {}):
  18.         try:
  19.             shell = cnf['shell']
  20.             del cnf['shell']
  21.         except KeyError:
  22.             try:
  23.                 shell = os.environ['SHELL']
  24.             except KeyError:
  25.                 shell = '/bin/sh'
  26.             shell = shell + ' -i'
  27.         args = string.split(shell)
  28.         shell = args[0]
  29.  
  30.         ScrolledText.__init__(self, master, cnf)
  31.         self.pos = '1.0'
  32.         self.bind('<Return>', self.inputhandler)
  33.         self.bind('<Control-c>', self.sigint)
  34.         self.bind('<Control-t>', self.sigterm)
  35.         self.bind('<Control-k>', self.sigkill)
  36.         self.bind('<Control-d>', self.sendeof)
  37.  
  38.         self.pid, self.fromchild, self.tochild = spawn(shell, args)
  39.         self.tk.createfilehandler(self.fromchild, TK_READABLE,
  40.                       self.outputhandler)
  41.  
  42.     def outputhandler(self, file, mask):
  43.         data = os.read(file, BUFSIZE)
  44.         if not data:
  45.             self.tk.deletefilehandler(file)
  46.             pid, sts = os.waitpid(self.pid, 0)
  47.             print 'pid', pid, 'status', sts
  48.             self.pid = None
  49.             detail = sts>>8
  50.             cause = sts & 0xff
  51.             if cause == 0:
  52.                 msg = "exit status %d" % detail
  53.             else:
  54.                 msg = "killed by signal %d" % (cause & 0x7f)
  55.                 if cause & 0x80:
  56.                     msg = msg + " -- core dumped"
  57.             Dialog(self.master, {
  58.                 'text': msg,
  59.                 'title': "Exit status",
  60.                 'bitmap': 'warning',
  61.                 'default': 0,
  62.                 'strings': ('OK',),
  63.             })
  64.             return
  65.         self.insert('end', data)
  66.         self.pos = self.index('end')
  67.         self.yview_pickplace('end')
  68.  
  69.     def inputhandler(self, *args):
  70.         if not self.pid:
  71.             Dialog(self.master, {
  72.                 'text': "No active process",
  73.                 'title': "No process",
  74.                 'bitmap': 'error',
  75.                 'default': 0,
  76.                 'strings': ('OK',),
  77.             })
  78.             return
  79.         self.insert('end', '\n')
  80.         line = self.get(self.pos, 'end')
  81.         self.pos = self.index('end')
  82.         os.write(self.tochild, line)
  83.  
  84.     def sendeof(self, *args):
  85.         if not self.pid:
  86.             Dialog(self.master, {
  87.                 'text': "No active process",
  88.                 'title': "No process",
  89.                 'bitmap': 'error',
  90.                 'default': 0,
  91.                 'strings': ('OK',),
  92.             })
  93.             return
  94.         os.close(self.tochild)
  95.  
  96.     def sendsig(self, sig):
  97.         if not self.pid:
  98.             Dialog(self.master, {
  99.                 'text': "No active process",
  100.                 'title': "No process",
  101.                 'bitmap': 'error',
  102.                 'default': 0,
  103.                 'strings': ('OK',),
  104.             })
  105.             return
  106.         os.kill(self.pid, sig)
  107.  
  108.     def sigint(self, *args):
  109.         self.sendsig(signal.SIGINT)
  110.  
  111.     def sigquit(self, *args):
  112.         self.sendsig(signal.SIGQUIT)
  113.  
  114.     def sigterm(self, *args):
  115.         self.sendsig(signal.SIGTERM)
  116.  
  117.     def sigkill(self, *args):
  118.         self.sendsig(signal.SIGKILL)
  119.  
  120. MAXFD = 100    # Max number of file descriptors (os.getdtablesize()???)
  121.  
  122. def spawn(prog, args):
  123.     p2cread, p2cwrite = os.pipe()
  124.     c2pread, c2pwrite = os.pipe()
  125.     pid = os.fork()
  126.     if pid == 0:
  127.         # Child
  128.         os.close(0)
  129.         os.close(1)
  130.         os.close(2)
  131.         if os.dup(p2cread) <> 0:
  132.             sys.stderr.write('popen2: bad read dup\n')
  133.         if os.dup(c2pwrite) <> 1:
  134.             sys.stderr.write('popen2: bad write dup\n')
  135.         if os.dup(c2pwrite) <> 2:
  136.             sys.stderr.write('popen2: bad write dup\n')
  137.         for i in range(3, MAXFD):
  138.             try:
  139.                 os.close(i)
  140.             except:
  141.                 pass
  142.         try:
  143.             os.execvp(prog, args)
  144.         finally:
  145.             print 'execvp failed'
  146.             os._exit(1)
  147.     os.close(p2cread)
  148.     os.close(c2pwrite)
  149.     return pid, c2pread, p2cwrite
  150.  
  151. def test():
  152.     shell = string.join(sys.argv[1:])
  153.     cnf = {}
  154.     if shell:
  155.         cnf['shell'] = shell
  156.     root = Tk()
  157.     root.minsize(1, 1)
  158.     w = ShellWindow(root, cnf)
  159.     w.pack({'expand': 1, 'fill': 'both'})
  160.     w.focus_set()
  161.     w.tk.mainloop()
  162.  
  163. if __name__ == '__main__':
  164.     test()
  165.